home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 2000-09-28 | 31.5 KB | 993 lines | [ TEXT/CWIE]
/* File: SetupGL.c Contains: Functions to enable building and destorying a GL full screen or windowed context Written by: Geoff Stahl (ggs) Copyright: Copyright © 1999 Apple Computer, Inc., All Rights Reserved Change History (most recent first): <7> 3/22/00 ggs remove extranious prototype <6> 3/21/00 ggs Added windowed mode and clean up various implementation details <5> 1/26/00 ggs Add fade code back in, ensure NULL pointer/context/drawable checks are in, add Preflight <4> 1/24/00 ggs Added glFinish to shutdown code <3> 1/24/00 ggs update to latest, better rendrere info handling for 3dfx, better checks on pause and resume, added frin devce numer and gdhandle from point <2.7> 11/28/99 ggs Split out DSp and error handling. Added texture memory considerations, assume VRAM is required if other than zero <2.6> 11/14/99 ggs Fix source server copy <2.5> 11/13/99 ggs fixed default pixel depth (0) condition that was causing failures <2.4> 11/13/99 ggs added custom fade code <2.3> 11/13/99 ggs Reset for Quake 3 use <2.2> 11/12/99 ggs re-add <2.1> 11/12/99 ggs added support for frequency retrieval, fixed display number output to be correct if display number input was -1 <2> 11/12/99 ggs 1.0 functionality <1> 11/11/99 ggs Initial Add Disclaimer: You may incorporate this sample code into your applications without restriction, though the sample code has been provided "AS IS" and the responsibility for its operation is 100% yours. However, what you are not permitted to do is to redistribute the source as "DSC Sample Code" after having made changes. If you're going to re-distribute the source, we require that you make it clear in the source that the code was descended from Apple Sample Code, but that you've made changes. */ // system includes ---------------------------------------------------------- // project includes --------------------------------------------------------- #include "Error Handler.h" #include "SetupDSp.h" #include "SetupGL.h" // globals (internal/private) ----------------------------------------------- const RGBColor rgbBlack = { 0x0000, 0x0000, 0x0000 }; const short kWindowType = kWindowDocumentProc; // prototypes (internal/private) -------------------------------------------- static Boolean CheckRenderer (GDHandle hGD, long *VRAM, long *textureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust); static Boolean CheckAllDeviceRenderers (long* pVRAM, long* pTextureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust); static Boolean CheckWindowExtents (GDHandle hGD, short width, short height); static void DumpCurrent (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, pstructGLInfo pcontextInfo); static GLenum BuildGLContext (AGLDrawable* paglDraw, AGLContext* paglContext, GDHandle hGD, pstructGLInfo pcontextInfo); static OSStatus BuildDrawable (AGLDrawable* paglDraw, GDHandle hGD, pstructGLInfo pcontextInfo); static OSStatus BuildGLonDevice (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, GDHandle hGD, pstructGLInfo pcontextInfo); static OSStatus BuildGLonDrawable (AGLDrawable aglDraw, AGLContext* paglContext, pstructGLWindowInfo pcontextInfo); // functions (internal/private) --------------------------------------------- // CheckRenderer // looks at renderer attributes it has at least the VRAM is accelerated // Inputs: hGD: GDHandle to device to look at // pVRAM: pointer to VRAM in bytes required; out is actual VRAM if a renderer was found, otherwise it is the input parameter // pTextureRAM: pointer to texture RAM in bytes required; out is same (implementation assume VRAM returned by card is total so we add texture and VRAM) // fAccelMust: do we check fro acceleration // Returns: true if renderer for the requested device complies, false otherwise static Boolean CheckRenderer (GDHandle hGD, long* pVRAM, long* pTextureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust) { AGLRendererInfo info, head_info; GLint inum; GLint dAccel = 0; GLint dVRAM = 0, dMaxVRAM = 0; Boolean canAccel = false, found = false; head_info = aglQueryRendererInfo(&hGD, 1); aglReportError (); if(!head_info) { ReportError ("aglQueryRendererInfo error"); return false; } else { info = head_info; inum = 0; // see if we have an accelerated renderer, if so ignore non-accelerated ones // this prevents returning info on software renderer when actually we'll get the hardware one while (info) { aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel); aglReportError (); if (dAccel) canAccel = true; info = aglNextRendererInfo(info); aglReportError (); inum++; } info = head_info; inum = 0; while (info) { aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel); aglReportError (); // if we can accel then we will choose the accelerated renderer // how about compliant renderers??? if ((canAccel && dAccel) || (!canAccel && (!fAccelMust || dAccel))) { aglDescribeRenderer(info, AGL_VIDEO_MEMORY, &dVRAM); // we assume that VRAM returned is total thus add texture and VRAM required aglReportError (); if (dVRAM >= (*pVRAM + *pTextureRAM)) { if (dVRAM >= dMaxVRAM) // find card with max VRAM { aglDescribeRenderer(info, AGL_DEPTH_MODES, pDepthSizeSupport); // which depth buffer modes are supported aglReportError (); dMaxVRAM = dVRAM; // store max found = true; } } } info = aglNextRendererInfo(info); aglReportError (); inum++; } } aglDestroyRendererInfo(head_info); if (found) // if we found a card that has enough VRAM and meets the accel criteria { *pVRAM = dMaxVRAM; // return VRAM return true; } // VRAM will remain to same as it did when sent in return false; } //----------------------------------------------------------------------------------------------------------------------- // CheckAllDeviceRenderers // looks at renderer attributes and each device must have at least one renderer that fits the profile // Inputs: pVRAM: pointer to VRAM in bytes required; out is actual min VRAM of all renderers found, otherwise it is the input parameter // pTextureRAM: pointer to texture RAM in bytes required; out is same (implementation assume VRAM returned by card is total so we add texture and VRAM) // fAccelMust: do we check fro acceleration // Returns: true if any renderer for on each device complies (not necessarily the same renderer), false otherwise static Boolean CheckAllDeviceRenderers (long* pVRAM, long* pTextureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust) { AGLRendererInfo info, head_info; GLint inum; GLint dAccel = 0; GLint dVRAM = 0, dMaxVRAM = 0; Boolean canAccel = false, found = false, goodCheck = true; // can the renderer accelerate, did we find a valid renderer for the device, are we still successfully on all the devices looked at long MinVRAM = 0x8FFFFFFF; // max long GDHandle hGD = GetDeviceList (); // get the first screen while (hGD && goodCheck) { head_info = aglQueryRendererInfo(&hGD, 1); aglReportError (); if(!head_info) { ReportError ("aglQueryRendererInfo error"); return false; } else { info = head_info; inum = 0; // see if we have an accelerated renderer, if so ignore non-accelerated ones // this prevents returning info on software renderer when actually we'll get the hardware one while (info) { aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel); aglReportError (); if (dAccel) canAccel = true; info = aglNextRendererInfo(info); aglReportError (); inum++; } info = head_info; inum = 0; while (info) { aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel); aglReportError (); // if we can accel then we will choose the accelerated renderer // how about compliant renderers??? if ((canAccel && dAccel) || (!canAccel && (!fAccelMust || dAccel))) { aglDescribeRenderer(info, AGL_VIDEO_MEMORY, &dVRAM); // we assume that VRAM returned is total thus add texture and VRAM required aglReportError (); if (dVRAM >= (*pVRAM + *pTextureRAM)) { if (dVRAM >= dMaxVRAM) // find card with max VRAM { aglDescribeRenderer(info, AGL_DEPTH_MODES, pDepthSizeSupport); // which depth buffer modes are supported aglReportError (); dMaxVRAM = dVRAM; // store max found = true; } } } info = aglNextRendererInfo(info); aglReportError (); inum++; } } aglDestroyRendererInfo(head_info); if (found) // if we found a card that has enough VRAM and meets the accel criteria { if (MinVRAM > dMaxVRAM) MinVRAM = dMaxVRAM; // return VRAM } else goodCheck = false; // one device failed thus entire requirement fails hGD = GetNextDevice (hGD); // get next device } // while if (goodCheck) // we check all devices and eeach was good { *pVRAM = dMaxVRAM; // return VRAM return true; } return false; //at least one device failed to have mins } //----------------------------------------------------------------------------------------------------------------------- // CheckWindowExtents // checks to see window fits on screen completely // Inputs: hGD: GDHandle to device to look at // width/height: requested width and height of window // Returns: true if window and borders fit, false otherwise static Boolean CheckWindowExtents (GDHandle hGD, short width, short height) { Rect strucRect, rectWin = {0, 0, 1, 1}; short deviceHeight = (**hGD).gdRect.bottom - (**hGD).gdRect.top - GetMBarHeight (); short deviceWidth = (**hGD).gdRect.right - (**hGD).gdRect.left; short windowWidthExtra, windowHeightExtra; // build window (not visible) WindowPtr pWindow = NewCWindow (NULL, &rectWin, "\p", true, kWindowType, (WindowPtr)-1, 0, 0); strucRect = (**(((WindowPeek)pWindow)->strucRgn)).rgnBBox; windowWidthExtra = (strucRect.right - strucRect.left) - 1; windowHeightExtra = (strucRect.bottom - strucRect.top) - 1; DisposeWindow (pWindow); if ((width + windowWidthExtra <= deviceWidth) && (height + windowHeightExtra <= deviceHeight)) return true; return false; } // -------------------------------------------------------------------------- // DumpCurrent // Kills currently allocated context // does not care about being pretty (assumes display is liekly faded) // Inputs: paglDraw, paglContext, pdspContext: things to be destroyed void DumpCurrent (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, pstructGLInfo pcontextInfo) { if (*pdspContext) DSpReportError (DSpContext_CustomFadeGammaOut (NULL, NULL, fadeTicks)); if (*paglContext) { aglSetCurrentContext (NULL); aglReportError (); aglSetDrawable (*paglContext, NULL); aglReportError (); aglDestroyContext (*paglContext); aglReportError (); *paglContext = NULL; } if (pcontextInfo->fmt) { aglDestroyPixelFormat (pcontextInfo->fmt); // pixel format is no longer needed aglReportError (); } pcontextInfo->fmt = 0; if (*paglDraw) DisposeWindow ((WindowPtr)*paglDraw); *paglDraw = NULL; DestroyDSpContext (pdspContext); // fades in } #pragma mark - // -------------------------------------------------------------------------- // BuildGLContext // Builds OpenGL context // Inputs: hGD: GDHandle to device to look at // pcontextInfo: request and requirements for cotext and drawable // Outputs: paglContext as allocated // pcontextInfo: allocated parameters // if fail to allocate: paglContext will be NULL // if error: will return error paglContext will be NULL static GLenum BuildGLContext (AGLDrawable* paglDraw, AGLContext* paglContext, GDHandle hGD, pstructGLInfo pcontextInfo) { OSStatus err = noErr; if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL { ReportError ("OpenGL not installed"); return noErr; } pcontextInfo->fmt = aglChoosePixelFormat (&hGD, 1, pcontextInfo->aglAttributes); // get an appropriate pixel format aglReportError (); if (NULL == pcontextInfo->fmt) { ReportError("Could not find valid pixel format"); return noErr; } *paglContext = aglCreateContext (pcontextInfo->fmt, NULL); // Create an AGL context aglReportError (); if (NULL == *paglContext) { ReportError ("Could not create context"); return paramErr; } // build window as late as possible err = BuildDrawable (paglDraw, hGD, pcontextInfo); if (err != noErr) { ReportError ("Could not build drawable"); return err; } if (!aglSetDrawable (*paglContext, *paglDraw)) // attach the CGrafPtr to the context return aglReportError (); if(!aglSetCurrentContext (*paglContext)) // make the context the current context return aglReportError (); return err; } // -------------------------------------------------------------------------- // BuildDrawable // Builds window to be used as drawable // Inputs: hGD: GDHandle to device to look at // pcontextInfo: request and requirements for cotext and drawable // Outputs: paglDraw as allocated // pcontextInfo: allocated parameters // if fail to allocate: paglDraw will be NULL // if error: will return error paglDraw will be NULL static OSStatus BuildDrawable (AGLDrawable* paglDraw, GDHandle hGD, pstructGLInfo pcontextInfo) { Rect rectWin; RGBColor rgbSave; GrafPtr pGrafSave; OSStatus err = noErr; // center window in our context's gdevice rectWin.top = (**hGD).gdRect.top + ((**hGD).gdRect.bottom - (**hGD).gdRect.top) / 2; // v center rectWin.top -= pcontextInfo->height / 2; rectWin.left = (**hGD).gdRect.left + ((**hGD).gdRect.right - (**hGD).gdRect.left) / 2; // h center rectWin.left -= pcontextInfo->width / 2; rectWin.right = rectWin.left + pcontextInfo->width; rectWin.bottom = rectWin.top + pcontextInfo->height; if (pcontextInfo->fFullscreen) *paglDraw = (AGLDrawable) NewCWindow (NULL, &rectWin, "\p", 0, plainDBox, (WindowPtr)-1, 0, 0); else *paglDraw = (AGLDrawable) NewCWindow (NULL, &rectWin, "\p", 0, kWindowType, (WindowPtr)-1, 0, 0); ShowWindow ((GrafPtr)*paglDraw); GetPort (&pGrafSave); SetPort ((GrafPtr)*paglDraw); GetForeColor (&rgbSave); RGBForeColor (&rgbBlack); PaintRect (&(*paglDraw)->portRect); RGBForeColor (&rgbSave); // ensure color is reset for proper blitting SetPort (pGrafSave); return err; } // -------------------------------------------------------------------------- // BuildGLonDevice // Takes device single device and tries to build on it // Inputs: hGD: GDHandle to device to look at // *pcontextInfo: request and requirements for cotext and drawable // Outputs: *paglDraw, *paglContext and *pdspContext as allocated // *pcontextInfo: allocated parameters // if fail to allocate: paglDraw, paglContext and pdspContext will be NULL // if error: will return error and paglDraw, paglContext and pdspContext will be NULL static OSStatus BuildGLonDevice (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, GDHandle hGD, pstructGLInfo pcontextInfo) { GLint depthSizeSupport; OSStatus err = noErr; Boolean fCheckRenderer = false; if (pcontextInfo->fFullscreen) { // if we are in 16 or 32 bit mode already, we can check the renderer now (we will double check later) if (16 <= (**(**hGD).gdPMap).pixelSize) { // check for VRAM and accelerated if (!CheckRenderer (hGD, &(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust)) { ReportError ("Renderer check failed"); return err; } else fCheckRenderer = true; } err = BuildDSpContext (pdspContext, hGD, depthSizeSupport, pcontextInfo); // we are now faded if ((err != noErr) || (*pdspContext == NULL)) { if (err != noErr) ReportErrorNum ("BuildDSpContext failed with error:", err); else ReportError ("Could not build DrawSprocket context"); if (*pdspContext) DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks)); return err; } } else { if (pcontextInfo->pixelDepth == 0) // default { pcontextInfo->pixelDepth = (**(**hGD).gdPMap).pixelSize; if (16 > pcontextInfo->pixelDepth) pcontextInfo->pixelDepth = 16; } if (pcontextInfo->fDepthMust && (pcontextInfo->pixelDepth != (**(**hGD).gdPMap).pixelSize)) // device depth must match and does not { ReportError ("Pixel Depth does not match device in windowed mode."); if (*pdspContext) DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks)); return err; } // copy back the curretn depth pcontextInfo->pixelDepth = (**(**hGD).gdPMap).pixelSize; if (!CheckWindowExtents (hGD, pcontextInfo->width, pcontextInfo->height)) { ReportError ("Window will not fit on device in windowed mode."); if (*pdspContext) DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks)); return err; } } // if we have not already checked the renderer, check for VRAM and accelerated if (!fCheckRenderer) if (!CheckRenderer (hGD, &(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust)) { ReportError ("Renderer check failed"); if (*pdspContext) DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks)); return err; } // do agl err = BuildGLContext (paglDraw, paglContext, hGD, pcontextInfo); if (*pdspContext) DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks)); return err; } // -------------------------------------------------------------------------- // BuildGLonDrawable // Takes a drawable and tries to build on it // Inputs: aglDraw: a valid AGLDrawable // *pcontextInfo: request and requirements for cotext and drawable // Outputs: *paglContext as allocated // *pcontextInfo: allocated parameters // if fail to allocate: paglContext will be NULL // if error: will return error and paglContext will be NULL static OSStatus BuildGLonDrawable (AGLDrawable aglDraw, AGLContext* paglContext, pstructGLWindowInfo pcontextInfo) { GDHandle hGD = NULL; short numDevices; GLint depthSizeSupport; OSStatus err = noErr; if (!aglDraw || !pcontextInfo) { ReportError ("NULL parameter passed to BuildGLonDrawable."); return paramErr; } // check renderere VRAM and acceleration numDevices = FindGDHandleFromWindow ((WindowPtr) aglDraw, &hGD); // so what do we do here? if (!pcontextInfo->fDraggable) // if numDevices > 1 then we will only using the software renderer otherwise check only window device { if ((numDevices > 1) || (numDevices == 0)) // this window spans mulitple devices thus will be software only { // infinite VRAM, infinite textureRAM, not accelerated if (pcontextInfo->fAcceleratedMust) { ReportError ("Unable to accelerate window that spans multiple devices"); return err; } } else // not draggable on single device { if (!CheckRenderer (hGD, &(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust)) { ReportError ("Renderer check failed"); return err; } } } // else draggable so must check all for support (each device should have at least one renderer that meets the requirements) else if (!CheckAllDeviceRenderers (&(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust)) { ReportError ("Renderer check failed"); return err; } // do agl if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL { ReportError ("OpenGL not installed"); return NULL; } // we successfully passed the renderer check if (!pcontextInfo->fDraggable && (numDevices == 1)) // not draggable on a single device pcontextInfo->fmt = aglChoosePixelFormat (&hGD, 1, pcontextInfo->aglAttributes); // get an appropriate pixel format else pcontextInfo->fmt = aglChoosePixelFormat (NULL, 0, pcontextInfo->aglAttributes); // get an appropriate pixel format aglReportError (); if (NULL == pcontextInfo->fmt) { ReportError("Could not find valid pixel format"); return NULL; } *paglContext = aglCreateContext (pcontextInfo->fmt, NULL); // Create an AGL context aglReportError (); if (NULL == *paglContext) { ReportError ("Could not create context"); return NULL; } if (!aglSetDrawable (*paglContext, aglDraw)) // attach the CGrafPtr to the context return aglReportError (); if(!aglSetCurrentContext (*paglContext)) // make the context the current context return aglReportError (); return err; } #pragma mark - // functions (public) ------------------------------------------------------- // PreflightGL // Checks for presense of OpenGL and DSp (if required) // Inputs: checkFullscreen: true if one wants to run fullscreen (which requires DrwSprocket currently) // Ouputs: true if OpenGL is installed (and DrawSprocket if checkFullscreen is true Boolean PreflightGL (Boolean checkFullscreen) { if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL return false; if (checkFullscreen && ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpStartup)) // check for existance of DSp return false; return true; } // -------------------------------------------------------------------------- // BuildGL // Takes device and geometry request and tries to build best context and drawable // if device does not work will walk down devices looking for first one that satisfies requirments // Inputs: *pnumDevice: 0 any device, # attempt that device first, then any device // *pcontextInfo: request and requirements for cotext and drawable // Outputs: *paglDraw, *paglContext and *pdspContext as allocated // *pnumDevice to device number in list that was used // *pcontextInfo: allocated parameters // if fail to allocate: paglDraw, paglContext and pdspContext will be NULL // if error: will return error and paglDraw, paglContext and pdspContext will be NULL OSStatus BuildGL (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, short* pnumDevice, pstructGLInfo pcontextInfo) { GDHandle hGD = NULL; OSStatus err = noErr; structGLInfo contextInfoSave; // clear *paglDraw = 0; *paglContext = 0; *pdspContext = 0; contextInfoSave = *pcontextInfo; // save info to reset on failures if (pcontextInfo->fFullscreen) { err = StartDSp (); if (gDSpStarted) gNeedFade = true; else return err; } //find main device if (*pnumDevice == -1) { GDHandle hDevice; // check number of screens hGD = GetMainDevice (); if (NULL != hGD) { err = BuildGLonDevice (paglDraw, paglContext, pdspContext, hGD, pcontextInfo); // find device number *pnumDevice = 0; hDevice = DMGetFirstScreenDevice (true); do { if (hDevice == hGD) break; hDevice = DMGetNextScreenDevice (hDevice, true); (*pnumDevice)++; } while (hDevice); if (!hDevice) ReportError ("main device match not found"); } else ReportError ("Cannot get main device"); } if ((err != noErr) || (*paglDraw == 0) || (*paglContext == 0)) { *pcontextInfo = contextInfoSave; // restore info //find target device and check this first is one exists if (*pnumDevice) { short i; hGD = DMGetFirstScreenDevice (true); for (i = 0; i < *pnumDevice; i++) { GDHandle hGDNext = DMGetNextScreenDevice (hGD, true); if (NULL == hGDNext) // ensure we did not run out of devices break; // if no more devices drop out else hGD = hGDNext; // otherwise continue } *pnumDevice = i; // record device we actually got err = BuildGLonDevice (paglDraw, paglContext, pdspContext, hGD, pcontextInfo); } } // while we have not allocated a context or there were errors if ((err != noErr) || (*paglDraw == 0) || (*paglContext == 0)) { DumpCurrent (paglDraw, paglContext, pdspContext, pcontextInfo); // dump what ever partial solution we might have *pcontextInfo = contextInfoSave; // restore info // now look through the devices in order hGD = DMGetFirstScreenDevice (true); *pnumDevice = -1; do { (*pnumDevice)++; err = BuildGLonDevice (paglDraw, paglContext, pdspContext, hGD, pcontextInfo); if ((err != noErr) || (*paglDraw == 0) || (*paglContext == 0)) // reset hGD only if we are not done { hGD = DMGetNextScreenDevice (hGD, true); DumpCurrent (paglDraw, paglContext, pdspContext, pcontextInfo); // dump what ever partial solution we might have *pcontextInfo = contextInfoSave; // restore info } } while (((err != noErr) || (*paglDraw == 0) || (*paglContext == 0)) && hGD); } return err; } // -------------------------------------------------------------------------- // DestroyGL // Destroys drawable and context // Ouputs: *paglDraw, *paglContext and *pdspContext should be 0 on exit OSStatus DestroyGL (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, pstructGLInfo pcontextInfo) { if ((!paglContext) || (!*paglContext)) return paramErr; // not a valid context glFinish (); DumpCurrent (paglDraw, paglContext, pdspContext, pcontextInfo); ShutdownDSp (); return noErr; } //----------------------------------------------------------------------------------------------------------------------- // BuildGLFromWindow // Takes window in the form of an AGLDrawable and geometry request and tries to build best context // Inputs: aglDraw: a valid AGLDrawable (i.e., a WindowPtr) // *pcontextInfo: request and requirements for cotext and drawable // Outputs: *paglContext as allocated // *pcontextInfo: allocated parameters // if fail to allocate: paglContext will be NULL // if error: will return error and paglContext will be NULL OSStatus BuildGLFromWindow (AGLDrawable aglDraw, AGLContext* paglContext, pstructGLWindowInfo pcontextInfo) { if (!aglDraw) return paramErr; return BuildGLonDrawable (aglDraw, paglContext, pcontextInfo); } // -------------------------------------------------------------------------- // DestroyGLFromWindow // Destroys context that waas allocated with BuildGLFromWindow // Ouputs: *paglContext should be NULL on exit OSStatus DestroyGLFromWindow (AGLContext* paglContext, pstructGLWindowInfo pcontextInfo) { OSStatus err; if ((!paglContext) || (!*paglContext)) return paramErr; // not a valid context glFinish (); aglSetCurrentContext (NULL); err = aglReportError (); aglSetDrawable (*paglContext, NULL); err = aglReportError (); aglDestroyContext (*paglContext); err = aglReportError (); *paglContext = NULL; if (pcontextInfo->fmt) { aglDestroyPixelFormat (pcontextInfo->fmt); // pixel format is no longer valid err = aglReportError (); } pcontextInfo->fmt = 0; return err; } //----------------------------------------------------------------------------------------------------------------------- // PauseGL // Pauses gl to allow toolbox drawing OSStatus PauseGL (AGLContext aglContext) { if (aglContext) { glFinish (); // must do this to ensure the queue is complete // aglSetDrawable(aglContext, NULL); aglSetCurrentContext (NULL); return aglReportError (); } return noErr; } //----------------------------------------------------------------------------------------------------------------------- // ResumeGL // resumes gl to allow gl drawing OSStatus ResumeGL (AGLDrawable aglDraw, AGLContext aglContext) { #pragma unused (aglDraw) if (aglContext) { aglSetCurrentContext (aglContext); // aglSetDrawable(aglContext, aglDraw); return aglReportError (); } return noErr; } // -------------------------------------------------------------------------- // FindGDHandleFromRect // Inputs: a global Rect // Outputs: the GDHandle that that Rect is mostly on // returns the number of devices that the Rect touches short FindGDHandleFromRect (Rect * pRect, GDHandle * phgdOnThisDevice) { Rect rectSect; long greatestArea, sectArea; short numDevices = 0; GDHandle hgdNthDevice; if (!phgdOnThisDevice) return NULL; *phgdOnThisDevice = NULL; hgdNthDevice = GetDeviceList (); greatestArea = 0; // check window against all gdRects in gDevice list and remember // which gdRect contains largest area of window} while (hgdNthDevice) { if (TestDeviceAttribute (hgdNthDevice, screenDevice)) if (TestDeviceAttribute (hgdNthDevice, screenActive)) { // The SectRect routine calculates the intersection // of the window rectangle and this gDevice // rectangle and returns TRUE if the rectangles intersect, // FALSE if they don't. SectRect (pRect, &(**hgdNthDevice).gdRect, &rectSect); // determine which screen holds greatest window area // first, calculate area of rectangle on current device sectArea = (long) (rectSect.right - rectSect.left) * (rectSect.bottom - rectSect.top); if (sectArea > 0) numDevices++; if (sectArea > greatestArea) { greatestArea = sectArea; // set greatest area so far *phgdOnThisDevice = hgdNthDevice; // set zoom device } hgdNthDevice = GetNextDevice(hgdNthDevice); } } return numDevices; } // -------------------------------------------------------------------------- // GetWindowDevice // Inputs: a valid WindowPtr // Outputs: the GDHandle that that window is mostly on // returns the number of devices that the windows content touches short FindGDHandleFromWindow (WindowPtr pWindow, GDHandle * phgdOnThisDevice) { GrafPtr pgpSave; Rect rectWind, rectSect; long greatestArea, sectArea; short numDevices = 0; GDHandle hgdNthDevice; if (!pWindow || !phgdOnThisDevice) return NULL; *phgdOnThisDevice = NULL; GetPort (&pgpSave); SetPort (pWindow); rectWind = pWindow->portRect; LocalToGlobal ((Point*)& rectWind.top); // convert to global coordinates LocalToGlobal ((Point*)& rectWind.bottom); hgdNthDevice = GetDeviceList (); greatestArea = 0; // check window against all gdRects in gDevice list and remember // which gdRect contains largest area of window} while (hgdNthDevice) { if (TestDeviceAttribute (hgdNthDevice, screenDevice)) if (TestDeviceAttribute (hgdNthDevice, screenActive)) { // The SectRect routine calculates the intersection // of the window rectangle and this gDevice // rectangle and returns TRUE if the rectangles intersect, // FALSE if they don't. SectRect (&rectWind, &(**hgdNthDevice).gdRect, &rectSect); // determine which screen holds greatest window area // first, calculate area of rectangle on current device sectArea = (long) (rectSect.right - rectSect.left) * (rectSect.bottom - rectSect.top); if (sectArea > 0) numDevices++; if (sectArea > greatestArea) { greatestArea = sectArea; // set greatest area so far *phgdOnThisDevice = hgdNthDevice; // set zoom device } hgdNthDevice = GetNextDevice(hgdNthDevice); } } SetPort (pgpSave); return numDevices; } //----------------------------------------------------------------------------------------------------------------------- // FindDeviceNumFromRect // returns the number of the device that the point is on (i.e., where it is in the search order) // just a ultility to find the number of the device from a point short FindDeviceNumFromRect (Rect * pRect) { short displayNum = 0; GDHandle hgdNthDevice, hgdFoundDevice; FindGDHandleFromRect (pRect, &hgdFoundDevice); hgdNthDevice = DMGetFirstScreenDevice (true); while (hgdNthDevice) { if (hgdFoundDevice == hgdNthDevice) break; hgdNthDevice = DMGetNextScreenDevice(hgdNthDevice, true); displayNum++; } // of WHILE return displayNum; }